using System;

namespace RTMP.SimpleClient.Helpers
{
    /// <summary>
    /// Span 帮助类，提供 Span 相关的扩展方法
    /// </summary>
    public static class SpanHelper
    {
        public static void SetBigEndianValue(this Span<byte> span, int value, int byteCount)
        {
            if (byteCount < 1 || byteCount > 4)
                throw new ArgumentOutOfRangeException(nameof(byteCount), "byteCount must be between 1 and 4");

            if (span.Length < byteCount)
                throw new ArgumentException("Span length is less than byteCount", nameof(span));

            for (int i = 0; i < byteCount; i++)
            {
                span[i] = (byte)((value >> (8 * (byteCount - 1 - i))) & 0xFF);
            }
        }

        public static void SetBigEndianValue(this Span<byte> span, uint value, int byteCount)
        {
            if (byteCount < 1 || byteCount > 4)
                throw new ArgumentOutOfRangeException(nameof(byteCount), "byteCount must be between 1 and 4");

            if (span.Length < byteCount)
                throw new ArgumentException("Span length is less than byteCount", nameof(span));

            for (int i = 0; i < byteCount; i++)
            {
                span[i] = (byte)((value >> (8 * (byteCount - 1 - i))) & 0xFFu);
            }
        }

        public static void SetLittleEndianValue(this Span<byte> span, int value, int byteCount)
        {
            if (byteCount < 1 || byteCount > 4)
                throw new ArgumentOutOfRangeException(nameof(byteCount), "byteCount must be between 1 and 4");

            if (span.Length < byteCount)
                throw new ArgumentException("Span length is less than byteCount", nameof(span));

            uint bits = unchecked((uint)value);
            for (int i = 0; i < byteCount; i++)
            {
                span[i] = (byte)((bits >> (8 * i)) & 0xFFu);
            }
        }

        public static void SetLittleEndianValue(this Span<byte> span, uint value, int byteCount)
        {
            if (byteCount < 1 || byteCount > 4)
                throw new ArgumentOutOfRangeException(nameof(byteCount), "byteCount must be between 1 and 4");

            if (span.Length < byteCount)
                throw new ArgumentException("Span length is less than byteCount", nameof(span));

            for (int i = 0; i < byteCount; i++)
            {
                span[i] = (byte)((value >> (8 * i)) & 0xFFu);
            }
        }

        // 64-bit variants
        public static void SetBigEndianValue(this Span<byte> span, long value, int byteCount)
        {
            if (byteCount < 1 || byteCount > 8)
                throw new ArgumentOutOfRangeException(nameof(byteCount), "byteCount must be between 1 and 8");

            if (span.Length < byteCount)
                throw new ArgumentException("Span length is less than byteCount", nameof(span));

            ulong bits = unchecked((ulong)value);
            for (int i = 0; i < byteCount; i++)
            {
                span[i] = (byte)((bits >> (8 * (byteCount - 1 - i))) & 0xFFul);
            }
        }

        public static void SetBigEndianValue(this Span<byte> span, ulong value, int byteCount)
        {
            if (byteCount < 1 || byteCount > 8)
                throw new ArgumentOutOfRangeException(nameof(byteCount), "byteCount must be between 1 and 8");

            if (span.Length < byteCount)
                throw new ArgumentException("Span length is less than byteCount", nameof(span));

            for (int i = 0; i < byteCount; i++)
            {
                span[i] = (byte)((value >> (8 * (byteCount - 1 - i))) & 0xFFul);
            }
        }

        public static void SetLittleEndianValue(this Span<byte> span, long value, int byteCount)
        {
            if (byteCount < 1 || byteCount > 8)
                throw new ArgumentOutOfRangeException(nameof(byteCount), "byteCount must be between 1 and 8");

            if (span.Length < byteCount)
                throw new ArgumentException("Span length is less than byteCount", nameof(span));

            ulong bits = unchecked((ulong)value);
            for (int i = 0; i < byteCount; i++)
            {
                span[i] = (byte)((bits >> (8 * i)) & 0xFFul);
            }
        }

        public static void SetLittleEndianValue(this Span<byte> span, ulong value, int byteCount)
        {
            if (byteCount < 1 || byteCount > 8)
                throw new ArgumentOutOfRangeException(nameof(byteCount), "byteCount must be between 1 and 8");

            if (span.Length < byteCount)
                throw new ArgumentException("Span length is less than byteCount", nameof(span));

            for (int i = 0; i < byteCount; i++)
            {
                span[i] = (byte)((value >> (8 * i)) & 0xFFul);
            }
        }

    }
}